/*
 * Copyright (C) 2011 The Android Open Source Project
 * Copyright 2014 linger1216
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.lid.lib;


import ohos.agp.colors.RgbColor;
import ohos.agp.components.*;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.text.Font;
import ohos.agp.utils.Color;
import ohos.agp.window.service.DisplayAttributes;
import ohos.agp.window.service.DisplayManager;
import ohos.app.Context;

import java.util.concurrent.atomic.AtomicInteger;

public class LabelView extends Text {

    private float _offsetx;
    private float _offsety;
    private float _anchorx;
    private float _anchory;
    private float _angel;
    private int _labelViewContainerID;



    public enum Gravity {
        LEFT_TOP, RIGHT_TOP
    }

    public LabelView(Context context) {
        this(context, null);
    }

    public LabelView(Context context, AttrSet attrs) {
        this(context, attrs, "");
    }

    public LabelView(Context context, AttrSet attrs, String defStyle) {
        super(context, attrs, defStyle);

        init();



    }


    private void init() {
        if (!(getLayoutConfig() instanceof ComponentContainer.LayoutConfig)) {
          StackLayout.LayoutConfig layoutParams =
                    new StackLayout.LayoutConfig(
                            ComponentContainer.LayoutConfig.MATCH_PARENT,
                            ComponentContainer.LayoutConfig.MATCH_CONTENT);
            setLayoutConfig(layoutParams);
        }

        _labelViewContainerID = -1;

        setTextColor(Color.WHITE);

        setFont(Font.DEFAULT_BOLD);
        setTextSize(15);

        ShapeElement background = new ShapeElement();
        background.setRgbColor(new RgbColor(0, 0, 255));
        setBackground(background);
    }

    public void setTargetView(Component target, int distance, Gravity gravity) {

        if (!replaceLayout(target)) {
            return;
        }

        final int d = dip2Px(distance);
        final Gravity g = gravity;
        final Component v = target;

        ComponentTreeObserver vto = getComponentTreeObserver();


        vto.addTreeLayoutChangedListener(new ComponentTreeObserver.GlobalLayoutListener() {
            @Override
            public void onGlobalLayoutUpdated() {
                getComponentTreeObserver().removeTreeLayoutChangedListener(this);
                calcOffset(getWidth(), d, g, v.getWidth(), false);
            }
        });

    }


    public void setTargetViewInBaseAdapter(Component target, int targetWidth, int distance, Gravity gravity) {
        if (!replaceLayout(target)) {
            return;
        }
           calcOffset(dip2Px(targetWidth), distance, gravity, targetWidth, true);
    }

    public void remove() {
        if (getComponentParent() == null || _labelViewContainerID == -1) {
            return;
        }

        ComponentContainer frameContainer = (ComponentContainer) getComponentParent();
        assert (frameContainer.getChildCount() == 2);
        Component target = frameContainer.getComponentAt(0);

        ComponentContainer parentContainer = (ComponentContainer) frameContainer.getComponentParent();
        int groupIndex = parentContainer.getChildIndex(frameContainer);
        if (frameContainer.getComponentParent() instanceof DependentLayout) {
            for (int i = 0; i < parentContainer.getChildCount(); i++) {
                if (i == groupIndex) {
                    continue;
                }
                Component view = parentContainer.getComponentAt(i);
                DependentLayout.LayoutConfig para = (DependentLayout.LayoutConfig) view.getLayoutConfig();
                for (int j = 0; j < para.getRules().length; j++) {
                    if (para.getRules()[j] == _labelViewContainerID) {
                        para.getRules()[j] = target.getId();
                    }
                }
                view.setLayoutConfig(para);
            }
        }

        ComponentContainer.LayoutConfig frameLayoutParam = frameContainer.getLayoutConfig();
        target.setLayoutConfig(frameLayoutParam);
        parentContainer.removeComponentAt(groupIndex);
        frameContainer.removeComponent(target);
        frameContainer.removeComponent(this);
        parentContainer.addComponent(target,groupIndex);
        _labelViewContainerID = -1;
    }

    private boolean replaceLayout(Component target) {
        if (getComponentParent() != null || target == null || target.getComponentParent() == null || _labelViewContainerID != -1) {
            return false;
        }

        ComponentContainer parentContainer = (ComponentContainer) target.getComponentParent();

        if (target.getComponentParent() instanceof StackLayout) {
            ((StackLayout) target.getComponentParent()).addComponent(this);
        } else if (target.getComponentParent() instanceof ComponentContainer) {

            int groupIndex = parentContainer.getChildIndex(target);
            _labelViewContainerID = generateViewId();


            if (target.getComponentParent() instanceof DependentLayout) {
                for (int i = 0; i < parentContainer.getChildCount(); i++) {
                    if (i == groupIndex) {
                        continue;
                    }
                    Component view = parentContainer.getComponentAt(i);
                    DependentLayout.LayoutConfig para = (DependentLayout.LayoutConfig) view.getLayoutConfig();
                    for (int j = 0; j < para.getRules().length; j++) {
                        if (para.getRules()[j] == target.getId()) {
                            para.getRules()[j] = _labelViewContainerID;
                        }
                    }
                    view.setLayoutConfig(para);
                }
            }
            parentContainer.removeComponent(target);


            StackLayout labelViewContainer = new StackLayout(getContext());
            ComponentContainer.LayoutConfig targetLayoutParam = target.getLayoutConfig();
            labelViewContainer.setLayoutConfig(targetLayoutParam);
            target.setLayoutConfig(new ComponentContainer.LayoutConfig(
                    ComponentContainer.LayoutConfig.MATCH_PARENT, ComponentContainer.LayoutConfig.MATCH_PARENT));


            labelViewContainer.addComponent(target);
            labelViewContainer.addComponent(this);
            labelViewContainer.setId(_labelViewContainerID);


            parentContainer.addComponent(labelViewContainer, groupIndex, targetLayoutParam);
        }
        return true;
    }

    private void calcOffset(int labelWidth, int distance, Gravity gravity, int targetWidth, boolean isDP) {

        int d = dip2Px(distance);
        int tw = isDP ? dip2Px(targetWidth) : targetWidth;

        float edge = (float) ((labelWidth - 2 * d) / (2 * 1.414));
        if (gravity == Gravity.LEFT_TOP) {
            _anchorx = -edge;
            _offsetx = _anchorx;
            _angel = -45;
        } else if (gravity == Gravity.RIGHT_TOP) {
            _offsetx = tw + edge - labelWidth;
            _anchorx = tw + edge;
            _angel = 45;
        }

        _anchory = (float) (1.414 * d + edge);
        _offsety = _anchory;


    }

    private int dip2Px(float dip) {
        DisplayAttributes attributes = DisplayManager.getInstance().getDefaultDisplay(getContext()).get().getAttributes();

        return (int)(dip*attributes.scalDensity+0.5f);

    }

    private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1);

    public static int generateViewId() {
        for (; ; ) {
            final int result = sNextGeneratedId.get();
            // aapt-generated IDs have the high byte nonzero; clamp to the range under that.
            int newValue = result + 1;
            if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0.
            if (sNextGeneratedId.compareAndSet(result, newValue)) {
                return result;
            }
        }
    }
}
